package com.codeckz.library_face.utils

import android.graphics.*
import androidx.camera.core.ImageProxy
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer


/**
 *@packageName com.codeckz.library_face.utils
 *@author kzcai
 *@date 2022/1/7
 */
object ImageUtils {

    /**
     * YUV_420_888转NV21
     *
     * @param image CameraX ImageProxy
     * @return byte array
     */
    fun yuv420ToNv21(image: ImageProxy): ByteArray {
        val planes = image.planes
        val yBuffer: ByteBuffer = planes[0].buffer
        val uBuffer: ByteBuffer = planes[1].buffer
        val vBuffer: ByteBuffer = planes[2].buffer
        val ySize: Int = yBuffer.remaining()
        val uSize: Int = uBuffer.remaining()
        val vSize: Int = vBuffer.remaining()
        val size = image.width * image.height
        val nv21 = ByteArray(size * 3 / 2)
        yBuffer.get(nv21, 0, ySize)
        vBuffer.get(nv21, ySize, vSize)
        val u = ByteArray(uSize)
        uBuffer.get(u)

        //每隔开一位替换V，达到VU交替
        var pos = ySize + 1
        for (i in 0 until uSize) {
            if (i % 2 == 0) {
                nv21[pos] = u[i]
                pos += 2
            }
        }
        return nv21
    }

    fun yuvToData(image: ImageProxy,rect: Rect,quality:Int = 70): ByteArray {
        val frame = image.toByteArray()
        val localYuvImage = YuvImage(frame, ImageFormat.NV21, image.width, image.height, null)
        val localByteArrayOutputStream = ByteArrayOutputStream()
        localYuvImage.compressToJpeg(
            rect,
            quality,
            localByteArrayOutputStream
        )
        val arrayOfByte: ByteArray = localByteArrayOutputStream.toByteArray()

        return  arrayOfByte
    }

    fun imageToBitmap(image: ImageProxy): ByteArray {


        val yBuffer = image.planes[0].buffer

        val uBuffer = image.planes[1].buffer
        val uStride = image.planes[1].pixelStride

        val vBuffer = image.planes[2].buffer
        val vStride = image.planes[2].pixelStride

        val buffer = ByteArray(image.width * image.height * 3 / 2)


        val rowStride = image.planes[0].rowStride
        val padding = rowStride - image.width
        var pos = 0

        if (padding == 0) {
            pos = yBuffer.remaining()
            yBuffer.get(buffer, 0, pos)
        } else {
            var yBufferPos = 0
            for (row in 0 until image.height) {
                yBuffer.position(yBufferPos)
                yBuffer.get(buffer, pos, image.width)
                yBufferPos += rowStride
                pos += image.width
            }
        }

        var i = 0

        val uRemaining = uBuffer.remaining()
        while (i < uRemaining) {
            buffer[pos++] = uBuffer[i]
            i += uStride

            if (padding == 0) continue

            val rowLen = i % rowStride
            if (rowLen >= image.width) {
                i += padding
            }
        }

        i = 0
        val vRemaining = vBuffer.remaining()
        while (i < vRemaining) {
            buffer[pos++] = vBuffer[i]
            i += vStride

            if (padding == 0) continue

            val rowLen = i % rowStride
            if (rowLen >= image.width) {
                i += padding
            }
        }

        val yuvImage = YuvImage(buffer, ImageFormat.NV21, image.width, image.height, null)
        val out = ByteArrayOutputStream()
        yuvImage.compressToJpeg(Rect(0, 0, yuvImage.width, yuvImage.height), 100, out)
        val imageBytes = out.toByteArray()
        return imageBytes
    }

    fun byteToBitmap(byteArray: ByteArray):Bitmap{
        return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
    }
}